home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / Sample Code / Snippets / Toolbox / DialogBits / DialogBits 2.0.1.c next >
Encoding:
C/C++ Source or Header  |  1992-07-23  |  32.3 KB  |  801 lines  |  [TEXT/MPS ]

  1. /* DialogBits
  2. * providing a bunch of dialog manager snippets */
  3. /*************************************************************
  4. This sample shows how to deal with many of the most commonly asked Dialog Manager
  5. questions.  Dimming edit lines, using userItems, restricting edit lines to
  6. specific lengths, and some other stuff is included here.
  7. The programming style used here is designed to clearly show the specific
  8. actions I'm taking, _not_ to show good coding practice.  Obviously, you will 
  9. want to modify and optimize this code for your specific application.
  10. C.K. Haun
  11. Apple Developer Tech Support
  12. *************************************************************/
  13. /*
  14. v 2.0.1 July '92
  15. Change for version 2.0.1
  16. Added a variable item, varies between static text and edit text.
  17.     Lots of folks have asked how to do this, and this shows the safest
  18.     way to do so.
  19.     Is this a good interface (switching between static and edit text)?
  20.     I dunno, I've had many people say "NO! Never do that!" and others say 
  21.     "Yeah, if it makes sense.".  I'm not making any value judgements, it's
  22.     your applications, if it makes sense to you have fun.
  23. */
  24.  
  25. /*
  26.  
  27. v 2.0 April '92
  28. Changes for version 2.0
  29. If available, use the new Dialog Manager routines.
  30. Added a control item
  31. Added code to check for DialogDispatch trap
  32. Added code to show how to check for 'Paste' in a size-limited edit field
  33.  
  34. */
  35.  
  36.  
  37. #include <Dialogs.h>
  38. #include <Controls.h>
  39. #include <QuickDraw.h>
  40. #include <Windows.h>
  41. #include <ToolUtils.h>
  42. #include <OSUtils.h>
  43. #include <Menus.h>
  44. #include <Fonts.h>
  45. #include <resources.h>
  46. #include <Sound.h>
  47. #include <Traps.h>
  48. #include <Gestaltequ.h>
  49. #include <Memory.h>
  50. #include <Scrap.h>
  51. #include <TextEdit.h>
  52. /* item numbers */
  53.  
  54. /* this stuff would normally be in your .h file, but in this simple example */
  55. /* I just put them here */
  56. /* I like enums, hate #defines */
  57. enum  {
  58.     /* ok and cancel are already defined in Dialogs.h */
  59.     kTitleItem = 3, 
  60.     kFredIconItem, 
  61.     kBottomEditLine, 
  62.     kSpinItem, 
  63.     kTopEditLine, 
  64.     kEditCheckBox, 
  65.     kDimmingBox,
  66.     kSayClickFred, 
  67.     kSayWhichVersItem, 
  68.     kScrollControlItem, 
  69.     kSayRotationSpeedItem, 
  70.     kSlowWordItem, 
  71.     kFastWordItem, 
  72.     /* 2.0.1 */
  73.     kStatTextVaryItem,
  74.     kEditTextVaryItem,
  75.     kVaryTextCheckBoxItem,
  76.     kBorderBox
  77. };
  78. enum  {
  79.     kSampleDialog = 128, 
  80.     kBaseSpinIcon = 129
  81. };
  82. enum  {
  83.     kSoundID = 128, 
  84.     kFredIconID = 128, 
  85.     kSysEnvironsVersion = 1, 
  86.     kNotWord = 128
  87. };
  88. /* key equates */
  89. enum  {
  90.     kEnterKey = 0x03, 
  91.     kTabKey = 9, 
  92.     kReturnKey = 0x0D, 
  93.     kBackSpace = 8, 
  94.     kEscKey = 0x1B, 
  95.     kLeftArrow = 0x1C, 
  96.     kRightArrow, 
  97.     kUpArrow,
  98.     kDownArrow, 
  99.     kDeleteKey = 0x7F
  100. };
  101.  
  102. /* prototypes */
  103. ControlHandle SnatchHandle(DialogPtr thebox, short theGetItem);
  104. void SpinIt(DialogPtr theDialog);
  105. pascal Boolean filterIt(DialogPtr inputDialog, EventRecord *myDialogEvent, short *theDialogItem);
  106. Boolean IsEditKey(char theKey, short modifiers);
  107. void IBeamIt(WindowPtr dwind);
  108. pascal void BorderDefault(WindowPtr dwind, short dinum);
  109. pascal void DimEditLine(WindowPtr dwind, short dinum);
  110. pascal void DoScrollArrows(ControlHandle theControl, short thePart);
  111. Boolean TrapAvailable(short tNumber, TrapType tType);
  112. short HasSelectionRange(DialogPeek inputDialog);
  113. pascal void NOPRoutine(WindowPtr dwind, short dinum);
  114.  
  115. /* These are the new Dialog Manager calls described in Tech note #304 */
  116. /* ONLY used if System 7 or later, of course */
  117. pascal OSErr GetStdFilterProc(ModalFilterProcPtr *theProc) = 
  118. {
  119.     0x303C, 0x0203, 0xAA68
  120. };
  121.  
  122.  
  123.  
  124.  
  125. /* Indicates to the dialog manager which item is default.  Will then alias the return key */
  126. /* to this item, and also bold border it for you (yaaaaa!) */
  127. pascal OSErr SetDialogDefaultItem(DialogPtr theDialog, short newItem)
  128. {
  129.     0x303C, 0x0304, 0xAA68
  130. };
  131.  
  132.  
  133.  
  134.  
  135. /* Indicates which item should be aliased to escape or Command - . */
  136. pascal OSErr SetDialogCancelItem(DialogPtr theDialog, short newItem)
  137. {
  138.     0x303C, 0x0305, 0xAA68
  139. };
  140.  
  141.  
  142.  
  143.  
  144. /* Tells the dialog manager that there is an edit line in this dialog, and */
  145. /* it should track and change to an I-Beam cursor when over the edit line */
  146. pascal OSErr SetDialogTracksCursor(DialogPtr theDialog, Boolean tracks) = 
  147. {
  148.     0x303C, 0x0306, 0xAA68
  149. };
  150.  
  151.  
  152.  
  153.  
  154. /* one global.  And it's not strictly necessary, this is set by a call to  */
  155. /* TrapAvailable to see if the new dialog dispatch routines are in. */
  156. /* So, you could call TrapAvail all the time instead of using this global */
  157. Boolean gNewDialog = true;
  158.  
  159. main()
  160. {
  161.     DialogPtr myDialog = nil;                               /* the dialog wee're using */
  162.     short hitItem = 0;                                      /* hitItem for ModalDialog */
  163.     Rect tempRect;                                          /* these  three are here for all the GetDItem/SetDItem calls*/
  164.     short tempItem;
  165.     Handle tempHandle;
  166.     Boolean tempBool;                                       /* a temporary boolean (now THAT'S a helpful comment */
  167.     Handle theSound;
  168.     Str255 tempString;
  169.     /* start up manahers */
  170.     InitGraf((Ptr)&qd.thePort);
  171.     InitFonts();
  172.     InitWindows();
  173.     InitMenus();
  174.     TEInit();
  175.     InitDialogs(nil);
  176.     InitCursor();
  177.     /* get our dialog.  It is created HIDDEN, and shown after I set all */
  178.     /* the user items to their functions */
  179.     myDialog = GetNewDialog(kSampleDialog, nil, (WindowPtr)-1);
  180.     
  181.     /* See if the DialogDispatch trap is available for using the new calls */
  182.     gNewDialog = TrapAvailable(_DialogDispatch, ToolTrap);
  183.     
  184.     /* add a NOT word to my string if they aren't */
  185.     if (gNewDialog == false) {
  186.         Handle theWord = GetResource('STR ', kNotWord);
  187.         if (theWord) {
  188.             HLock(theWord);
  189.             ParamText((Str255)*theWord, "", "", "");
  190.             HUnlock(theWord);
  191.             ReleaseResource(theWord);
  192.         }
  193.     }
  194.     /* set up our user items for various things */
  195.     
  196.     /* Switch here for Sys 7 or prior */
  197.     /* We'll set up our default and cancel items for gNewDialog, and also shorten */
  198.     /* the DITL to remove the user item I had in there to border the OK button */
  199.     /* Testing for System 7 is appropriate for the new DM calls, but for the */
  200.     /* Append/Delete DITL calls there is a specific selector, so we'll use that also */
  201.     if (gNewDialog) {
  202.         long gestaltReturn;
  203.         OSErr myErr;
  204.         SetDialogDefaultItem(myDialog, ok);
  205.         SetDialogCancelItem(myDialog, cancel);
  206.         SetDialogTracksCursor(myDialog, true);
  207.         
  208.         /* If we have the new calls, we can (and should) take the bounding */
  209.         /* box user item off our item list */
  210.         /* see if ShortenDILT exisits */
  211.         myErr = Gestalt(gestaltDITLExtAttr, &gestaltReturn);
  212.         if ((myErr == noErr) && (gestaltReturn & 0x1)) {
  213.             ShortenDITL(myDialog, 1);
  214.         } else {
  215.             
  216.             /* something weird happened, we have the new Dialog calls but not  */
  217.             /* shortenDITL.  So make the bounding box item a NOP, but we still */
  218.             /* MUST have it point to something */
  219.             GetDItem(myDialog, kBorderBox, &tempItem, &tempHandle, &tempRect);
  220.             SetDItem(myDialog, kBorderBox, tempItem, (Handle)NOPRoutine, &tempRect);
  221.             
  222.         }
  223.     } else {
  224.         /* no new calls, set up the bordering box ourselves */
  225.         GetDItem(myDialog, kBorderBox, &tempItem, &tempHandle, &tempRect);
  226.         SetDItem(myDialog, kBorderBox, tempItem, (Handle)BorderDefault, &tempRect);
  227.     }
  228.     
  229.     /* set up the user item that will dim the edit line when it is disabled */
  230.     GetDItem(myDialog, kDimmingBox, &tempItem, &tempHandle, &tempRect);
  231.     SetDItem(myDialog, kDimmingBox, tempItem, (Handle)DimEditLine, &tempRect);
  232.     
  233.     /* make sure the enabled checkbox for the edit line is FALSE */
  234.     tempHandle = (Handle)SnatchHandle(myDialog, kEditCheckBox);
  235.     SetCtlValue((ControlHandle)tempHandle, false);
  236.     
  237.     /* and since I want this edit line dimmed when the box first shows up, I'll */
  238.     /* select the other edit line */
  239.     SelIText((DialogPtr)myDialog, kTopEditLine, 0, 0);
  240.     /* 2.0.1 adding switchable text*/
  241.     HideDItem(myDialog,kEditTextVaryItem);
  242.     
  243.     
  244.     /* show it */
  245.     ShowWindow((WindowPtr)myDialog);
  246.     
  247.     /* draw it once */
  248.     DrawDialog(myDialog);
  249.     
  250.     do {
  251.         ModalDialog((ModalFilterProcPtr)filterIt, &hitItem);
  252.         switch (hitItem) {
  253.             case kFredIconItem:
  254.                 /* if they click on Fred, have him express his opinion */
  255.                 theSound = GetResource('snd ', kSoundID);
  256.                 if (theSound != nil) {
  257.                     SndPlay(nil, theSound, false);
  258.                     ReleaseResource(theSound);
  259.                 }
  260.                 break;
  261.             case kEditCheckBox:
  262.                 /* edit line dim checkbox */
  263.                 
  264.                 tempHandle = (Handle)SnatchHandle(myDialog, kEditCheckBox);
  265.                 tempBool = GetCtlValue((ControlHandle)tempHandle);
  266.                 tempBool ? tempBool = false : tempBool = true;
  267.                 SetCtlValue((ControlHandle)tempHandle, tempBool);
  268.                 if (tempBool == false) {
  269.                     /* they turned the edit line off, we need to switch out of the EL if its */
  270.                     /* active */
  271.                     if (((DialogPeek)myDialog)->editField + 1 == kBottomEditLine)
  272.                         SelIText((DialogPtr)myDialog, kTopEditLine, 0, 0);
  273.                 }
  274.                 /* whatever they did, invalidate the rect so the edit line is dimmed/not  */
  275.                 /* dimmed correctly */
  276.                 GetDItem(myDialog, kDimmingBox, &tempItem, &tempHandle, &tempRect);
  277.                 /* way paranoid, but once you've invalidated a rect in the wrong port */
  278.                 /* you never want to do it again */
  279.                 SetPort(myDialog);
  280.                 InvalRect(&tempRect);
  281.                 break;
  282.             case kVaryTextCheckBoxItem:
  283.             tempHandle = (Handle)SnatchHandle(myDialog, kVaryTextCheckBoxItem);
  284.                 tempBool = GetCtlValue((ControlHandle)tempHandle);
  285.                 tempBool = tempBool ? false : true;
  286.                 SetCtlValue((ControlHandle)tempHandle,tempBool);
  287.                 if(tempBool){
  288.                 HideDItem(myDialog,kStatTextVaryItem);
  289.                 ShowDItem(myDialog,kEditTextVaryItem);
  290.                 } else {
  291.                 /* when we switch from edit text to static text, we want the */            
  292.                 /* static text to say the same thing as the edit text, so let's do that */
  293.                 GetIText((Handle)SnatchHandle(myDialog, kEditTextVaryItem), tempString);
  294.                 SetIText((Handle)SnatchHandle(myDialog, kStatTextVaryItem),tempString);
  295.                 HideDItem(myDialog,kEditTextVaryItem);
  296.                 ShowDItem(myDialog,kStatTextVaryItem);
  297.                 
  298.                 }
  299.             /* whatever we did with this, we have to change the selection */    
  300.             if(tempBool){
  301.             /* if they just turned us on, move the selection to us */
  302.             SelIText((DialogPtr)myDialog, kEditTextVaryItem, 0, 0);
  303.         
  304.             } else {
  305.             /* else move to the top line */
  306.                SelIText((DialogPtr)myDialog, kTopEditLine, 0, 0);
  307.             
  308.             }
  309.             break;
  310.                 
  311.         }
  312.     }
  313.             while (hitItem != ok && hitItem != cancel);
  314.     DisposDialog(myDialog);
  315.     InitCursor();                                           /* Init to prevent I-beam from hanging around in some circumstances */
  316. } /* end main */
  317.  
  318. /* My dialog filter.  It's pretty crowded here, since I'm showing lots of */
  319. /* stuff.  You'd of course want it neatened up a bit */
  320. pascal Boolean filterIt(DialogPtr inputDialog, EventRecord *myDialogEvent, short *theDialogItem)
  321. {
  322.     WindowPtr tempWindowPtr;
  323.     ModalFilterProcPtr theModalProc;
  324.     char theKey;
  325.     Rect tempRect;
  326.     short tempItem;
  327.     Handle tempHandle;
  328.     long tilticks;
  329.     Boolean returnVal = false;
  330.     char tempKey;
  331.     Str255 myStr;
  332.     long offset;
  333.     short selection;
  334.     long scrapLen;
  335.     short resultLen;
  336.     Point mousePoint;
  337.     Boolean hiLit = false;
  338.     Point tempPoint;
  339.     short thePart;
  340.     ControlHandle returnedControl;
  341.     OSErr myErr;
  342.     Boolean wasAKey = false;    
  343.     /* save the current port, and set the port to us */
  344.     GetPort(&tempWindowPtr);
  345.     SetPort(inputDialog);
  346.     
  347.     /**********************************************************************/
  348.     /* Use something like this if you want to do any idle time drawing in your */
  349.     /* dialog, like a clock, flashing cursor, or a classy animated icon like I'm using */
  350.     /**********************************************************************/
  351.     SpinIt(inputDialog);
  352.     
  353.     /**********************************************************************
  354.     IBeamIt changes the cursor to an IBeam cursor when the cursor is over
  355.     the active edit line.
  356.     Of course, if we're in System 7, we have already made the DialogTracksCursor
  357.     call, so we don't need this.
  358.     **********************************************************************/
  359.     if (gNewDialog == false)
  360.         IBeamIt(inputDialog);
  361.     
  362.     /*************************************************************/
  363.     /* Some key filtering schemes follow.  The first is the standard filter to */
  364.     /* recognize 'return' as OK and 'ESC' as cancel.  What this really means */
  365.     /* is that I never ever want to have to use the mouse to click the cancel */
  366.     /* buttton ever again, you can just cut and paste this code from now on. */
  367.     /***********************************************************************/
  368.     /* do standard filtering for escape and return as OK and Cancel aliases */
  369.     /* We also invert the button in the dialog, so the user get's visual feedback */
  370.     /* about the action they just took */
  371.     /* Again, if we're using the new calls, then we don't need to do this particular */
  372.     /* filtering */
  373.     wasAKey = (myDialogEvent->what == keyDown) || (myDialogEvent->what == autoKey);
  374.         /* this 'if' has a double key check because of the 'tab' key restriction */
  375.         /* I'm doing.  If the new dialog manager calls are being used, we do NOT */
  376.         /* want to pass the tab key through to the standard filter, since it will */
  377.         /* tab to the other edit line even if we have it turned off */
  378.     if ((gNewDialog == false || (wasAKey && ((myDialogEvent->message & charCodeMask) == kTabKey)) ) && wasAKey) {
  379.         theKey = myDialogEvent->message & charCodeMask;
  380.         switch (theKey) {
  381.             case kReturnKey:
  382.             case kEnterKey:                                 /* enter key */
  383.                 /* This filters for Return or Enter as item 1, and Esc as item 2 */
  384.                 *theDialogItem = ok;                        /* change whatever the current item is to the OK item */
  385.                 /* now we need to invert the button */
  386.                 HiliteControl(SnatchHandle(inputDialog, ok), inButton);
  387.                 Delay(8, &tilticks);                        /* wait about 8 ticks so they can see it */
  388.                 HiliteControl(SnatchHandle(inputDialog, ok), false);
  389.                 SetPort(tempWindowPtr);
  390.                 returnVal = true;
  391.                 break;
  392.                 /* This filters the escape key as the same as item 2 (the canx button, usually ) */
  393.             case kEscKey:
  394.                 *theDialogItem = cancel;
  395.                 HiliteControl(SnatchHandle(inputDialog, cancel), inButton);
  396.                 Delay(8, &tilticks);                        /* wait about 8 ticks so they can see it */
  397.                 HiliteControl(SnatchHandle(inputDialog, cancel), false);
  398.                 returnVal = true;
  399.                 break;
  400.             case kTabKey:
  401.                 /* I'm filtering the tab key here so the user cannot tab to */
  402.                 /* my inactive edit line */
  403.                 if (GetCtlValue((ControlHandle)SnatchHandle(inputDialog, kEditCheckBox)) == false){
  404.                 
  405.                     returnVal = true;                       /* don't allow edit line swaps */}
  406.                 break;
  407.         }
  408.     }
  409.     
  410.     /********************************************************************************/
  411.     /* Here's another kind of key filtering you need every so often, text or numeric */
  412.     /* filtering.  In this case, we're only going to allow non-numeric characters in */
  413.     /* the second edit line we have installed in this dialog */
  414.     /* Any number will be eaten, and a beep generated */
  415.     /**************************************************/
  416.     if (wasAKey) {
  417.         theKey = myDialogEvent->message & charCodeMask;
  418.         
  419.         if ((theKey > 0x30 && theKey < 0x39) && ((DialogPeek)inputDialog)->editField + 1 == kBottomEditLine) {
  420.             /* Dang, it's a number and in the wrong edit line, reject it */
  421.             SysBeep(1);                                     /* complain a little */
  422.             returnVal = true;                               /* tell the dialog manager */
  423.                                                             /* that we handled this already and */
  424.             /* it doesn't have to, so the keystroke will _not_ get */
  425.             /* added to the edit line */
  426.             
  427.         }
  428.     }
  429.     
  430.     /********************************************************************************/
  431.     /* Here's yet another kind of key filtering you need every so often.  */
  432.     /* I'm going to restrict the amount of text in the top edit line to just 25 characters */
  433.     /**************************************************/
  434.     /* •• NOTE: Remember Cut/Copy/Paste! */
  435.     /* Before you allow these, you need to see what the result of a Paste (in this case) */
  436.     /* will be, since a Paste can also drive you over the 25 char limit. */
  437.     /* I've modified the function IsEditKey to look for these */
  438.     /* I've also added code that checks to see if there is a selection range, */
  439.     /* since typeing one charater to replace 5 is OK */
  440.     
  441.     /* First, see if it was a key and the top edit line is active */
  442.     if ((wasAKey) && ((DialogPeek)inputDialog)->editField + 1 == kTopEditLine) {
  443.         selection = HasSelectionRange((DialogPeek)inputDialog);
  444.         scrapLen = GetScrap(nil, 'TEXT', &offset);
  445.         GetDItem(inputDialog, kTopEditLine, &tempItem, &tempHandle, &tempRect);
  446.         GetIText(tempHandle, myStr);
  447.         /* calculate the result of adding the scrap to the current record.  We use */
  448.         /* this in a few places here */
  449.         resultLen = myStr[0] + (scrapLen - selection);
  450.         theKey = myDialogEvent->message & charCodeMask;
  451.         tempKey = theKey;
  452.         if (tempKey >= 0x61 && tempKey <= 0x7a)
  453.             tempKey -= 0x20;
  454.         if (myStr[0] > 25) {                                /* over 25, see what it is */
  455.             if (IsEditKey(theKey, myDialogEvent->modifiers)) {
  456.                 /* it was an editing key, but it MAY be a command-V. */
  457.                 /* If it's a command-V then we won't allow it UNLESS */
  458.                 /* there is a slection range AND the new data won't overrun things */
  459.                 if ((tempKey == 'V') && (myDialogEvent->modifiers & cmdKey)) {
  460.                     
  461.                     /* this was a paste.  check selection range and scrap len  */
  462.                     if (resultLen < 26) {
  463.                         returnVal = false;                  /* net result is  25 or less */
  464.                     } else {
  465.                         SysBeep(1);
  466.                         returnVal = true;
  467.                     }
  468.                 } else {
  469.                     returnVal = false;                      /* don't filter out editing keys */
  470.                 }
  471.             } else {
  472.                 /* One more check (this can get complicated, huh?) */
  473.                 /* We now look to see if there is a selection range.  If there */
  474.                 /* is a range of 1 or more characters, then the one character they are entering */
  475.                 /* now will replace that, and we'll end up with _less_ than 25 (or equal) */
  476.                 /* to do this, we have to get the TERecord out of the dialog.  */
  477.                 /* I'm going to do this in a seperate function */
  478.                 if (selection == nil) {
  479.                     SysBeep(1);                             /* complain a little */
  480.                     returnVal = true;                       /* tell the dialog manager that we handled this already and */
  481.                     /* it doesn't have to, so the keystroke will _not_ get */
  482.                     /* added to the edit line */
  483.                 }
  484.             }
  485.         } else {
  486.             /* even if we're less than 25 currently, a Command-V (paste) could put us over */
  487.             /* so check it out */
  488.             
  489.             if ((tempKey == 'V') && (myDialogEvent->modifiers & cmdKey)) {
  490.                 
  491.                 /* Gettting the scrap with a nil handle, which does not give us data, just */
  492.                 /* returns the size */
  493.                 if (resultLen > 25) {
  494.                     SysBeep(1);                             /* complain a little */
  495.                     returnVal = true;                       /* tell the dialog manager that we handled this already and */
  496.                     
  497.                 }
  498.             }
  499.         }
  500.     }
  501.     /* We are doing three checks here in the dialog filter for  mouseDown */
  502.     /* events. */
  503.     /* The first checks to see if we're in the icon of that Charismatic Dude */
  504.     /* Fred, and tracks it like a control if we are. */
  505.     /* If we're not, then we may be in our scroll bar, and we have to */
  506.     /* do various things if that is true. */
  507.     /* Or, we may be in the disabled edit line, and we have to disallow clicks on it */
  508.     /* when it's disabled */
  509.     
  510.     if (myDialogEvent->what == mouseDown) {
  511.         mousePoint = (myDialogEvent->where);
  512.         GlobalToLocal(&mousePoint);
  513.         /* First see if we're in Fred */
  514.         GetDItem(inputDialog, kFredIconItem, &tempItem, &tempHandle, &tempRect);
  515.         if (PtInRect(mousePoint, &tempRect)) {
  516.             /* invert my icon, and track it whilst the user holds the mouse down */
  517.             InvertRect(&tempRect);
  518.             hiLit = true;
  519.             while (StillDown()) {
  520.                 GetMouse(&tempPoint);                       /* returns point in local coords */
  521.                 if (PtInRect(tempPoint, &tempRect)) {
  522.                     /* in the rect.  See if it's hilighted or not */
  523.                     if (hiLit == false) {
  524.                         hiLit = true;
  525.                         InvertRect(&tempRect);
  526.                     }
  527.                 } else {
  528.                     /* not in the rectangle.  If it's hilit, get rid of that */
  529.                     if (hiLit == true) {
  530.                         hiLit = false;
  531.                         InvertRect(&tempRect);
  532.                     }
  533.                 }
  534.             }
  535.             if (hiLit == true) {
  536.                 /* if it's still hilited when the mouse comes up, then that means the */
  537.                 /* user stayed in and wants to take this icon action */
  538.                 InvertRect(&tempRect);                      /* clear the hiliting if it's still lit */
  539.                 *theDialogItem = kFredIconItem;
  540.                 returnVal = true;                           /* telling the Dialog Manager we handled it, pass item back */
  541.             }
  542.         } else {
  543.             /* Now see if we're in the scroll bar  */
  544.             
  545.             GetDItem(inputDialog, kScrollControlItem, &tempItem, &tempHandle, &tempRect);
  546.             if (PtInRect(mousePoint, &tempRect)) {
  547.                 /* We're in the scroll bar. */
  548.                 /* Now, what does that mean???? */
  549.                 /* Well, the Dialog Manager will automatically call FindControl and TrackControl */
  550.                 /* and set the control value (in the case of scroll thumbs) */
  551.                 /* on controls added to your dialog, and in many cases that's all you're going */
  552.                 /* to need. */
  553.                 /* But, ModalDialog does NOT pass back a part code, so if the userPerson */
  554.                 /* clicked on the thumb or arrows of the scroll bar, you won't know, you'll */
  555.                 /* just know that the  scroll bar was clicked in.*/
  556.                 /* That's not enough, so we'll to an initial check to see where the control */
  557.                 /* was hit */
  558.                 thePart = FindControl(mousePoint, inputDialog, &returnedControl);
  559.                 /* if the hit was in an arrow or page area, we'll handle it ourselfs */
  560.                 if (thePart != inThumb) {
  561.                     TrackControl(returnedControl, mousePoint, (ProcPtr)DoScrollArrows);
  562.                     returnVal = true;
  563.                 }
  564.                 /* if it was in the thumb, we'll just fall through and let the Dialog Manager */
  565.                 /* handle it for us */
  566.             } else {
  567.                 /* first see if we even care about this click.  If the check box is true, then */
  568.                 /* both edit lines are active, let the dialog manager handle it */
  569.                 if (GetCtlValue(SnatchHandle(inputDialog, kEditCheckBox))) {
  570.                     returnVal = false;                      /* DM will handle */
  571.                 } else {
  572.                     /* OK, so the edit line checkbox is NOT set, which means that we don't want */
  573.                     /* hits in the inactive edit line to do anything.  So, see if the hit was */
  574.                     /* in the edit line, and report 'true' if it was, telling the Dialog Manager that */
  575.                     /* you handled the event and it should do nothing */
  576.                     GetDItem(inputDialog, kBottomEditLine, &tempItem, &tempHandle, &tempRect);
  577.                     if (PtInRect(mousePoint, &tempRect)) {
  578.                         returnVal = true;
  579.                     } else {
  580.                         returnVal = false;
  581.                     }
  582.                 }
  583.             }
  584.         }
  585.     }
  586.     /* one final thing if we're under System 7, */
  587.     /* calling the standard filter. */
  588.     /* You MUST call the standard filter if you want any of the  */
  589.     /* new things to happen! */
  590.     /* The OK button border, cursor tracking, and the rest ONLY */
  591.     /* happen if you call the filter! */
  592.     /* I am also only doing this if the returnValue is still false.  If I have */
  593.     /* set it to true somewhere in here, I don't want to call the stdFilter */
  594.     if (gNewDialog && !returnVal) {
  595.         
  596.         myErr = GetStdFilterProc(&theModalProc);
  597.         if (myErr == noErr)
  598.             returnVal = theModalProc(inputDialog, myDialogEvent, theDialogItem);
  599.     }
  600.     return(returnVal);
  601. } /* end filterIt */
  602.  
  603. /* SpinIt animates my fancy icon */
  604. void SpinIt(DialogPtr theDialog)
  605. {
  606.     static short pos;
  607.     static long count;
  608.     Handle myIcon;
  609.     Rect tempRect;
  610.     short tempItem;
  611.     Handle tempHandle;
  612.     /* I'm adjusting the speed of the spin based on the value of the scroll bar */
  613.     if (TickCount() > count + (10 - GetCtlValue(SnatchHandle(theDialog, kScrollControlItem)))) {
  614.         count = TickCount();                                /* reset count to next value */
  615.         myIcon = GetIcon(pos + kBaseSpinIcon);
  616.         /* you could have a rect in this function, but that'd require you to change it all 
  617.         * the time when you move the item around in your dialog.  So, we'll reference it 
  618.         * from the dialog record instead */
  619.         /* make sure we really got the handle */
  620.         if (myIcon != nil) {
  621.             GetDItem(theDialog, kSpinItem, &tempItem, &tempHandle, &tempRect);
  622.             PlotIcon(&tempRect, myIcon);
  623.             ReleaseResource(myIcon);
  624.         }
  625.         pos++;
  626.         if (pos > 3)
  627.             pos = 0;
  628.     }
  629. } /* end SpinIt */
  630.  
  631. /* BorderDefault draws a heavy border around the default button (in this case the OK button ) */
  632. /* Again, not necessary if the new DM calls are in */
  633. pascal void BorderDefault(WindowPtr dwind, short dinum)
  634. {
  635. #pragma unused (dinum)
  636.     short itemtype;
  637.     Handle itemhandle;
  638.     Rect borderRect;
  639.     GetDItem(dwind, ok, &itemtype, &itemhandle, &borderRect);
  640.     /* ok is defined as 1 in the interfaces.  If you'd like another item outlined, */
  641.     /* change this number, of course. */
  642.     InsetRect(&borderRect, -4, -4);
  643.     PenSize(3, 3);
  644.     FrameRoundRect(&borderRect, 16, 16);
  645.     PenSize(1, 1);
  646. } /* end BorderDefault */
  647.  
  648. /* This userItem dims the bottom edit line if the check box is not checked */
  649. pascal void DimEditLine(WindowPtr dwind, short dinum)
  650. {
  651.     ControlHandle tempCont;
  652.     tempCont = SnatchHandle(dwind, kEditCheckBox);
  653.     /* only do it if the checkbox is false */
  654.     if (GetCtlValue(tempCont) == false) {
  655.         PenState thePen;
  656.         short itemType;
  657.         Handle itemHandle;
  658.         Rect dimRect;
  659.         /* Save and restore the pen state so we don't mess things up for other */
  660.         /* drawing routines */
  661.         GetPenState(&thePen);
  662.         GetDItem(dwind, dinum, &itemType, &itemHandle, &dimRect);
  663.         PenMode(notPatBic);
  664.         PenPat(&qd.gray);
  665.         PaintRect(&dimRect);
  666.         SetPenState(&thePen);
  667.         
  668.     }
  669. } /* end DimEditLine */
  670.  
  671. /* a little utility to see if the current key is an edit-type key */
  672. Boolean IsEditKey(char theKey, short modifiers)
  673. {
  674.     register qq;
  675.     Boolean returnVal = false;
  676.     char editChars[] =  {
  677.         kLeftArrow, kUpArrow, kRightArrow, kDownArrow, kBackSpace, kEscKey
  678.     };
  679.     char commandEdits[] =  {
  680.         'C', 'V', 'P'
  681.     };
  682.     for (qq = 0; qq < sizeof(editChars) / sizeof(char); qq++) {
  683.         if (theKey == editChars[qq])
  684.             returnVal = true;
  685.     }
  686.     if (returnVal != true && (modifiers & cmdKey)) {
  687.         /* check for XCP */
  688.         /* Do you want me to use toupper?  What! And link in all of StdLib! aggggg */
  689.         if (theKey >= 0x61 && theKey <= 0x7a)
  690.             theKey -= 0x20;
  691.         for (qq = 0; qq < sizeof(commandEdits) / sizeof(char); qq++) {
  692.             if (theKey == commandEdits[qq])
  693.                 returnVal = true;
  694.         }
  695.     }
  696.     return(returnVal);
  697. } /* end IsEditKey */
  698.  
  699. /* changes the cursor to an IBeam if it's over an active edit line, or to the */
  700. /* arrow if it's not */
  701. /* Again, not necessary if the new DM calls are in */
  702. void IBeamIt(WindowPtr dwind)
  703. {
  704.     Point mouseAt;
  705.     short itemtype;
  706.     Handle itemhandle;
  707.     Rect borderRect;
  708.     short itemNum;
  709.     /* first get the current edit line out of the dialog record */
  710.     itemNum = ((DialogPeek)dwind)->editField + 1;           /* always stored 1 less */
  711.     GetDItem(dwind, itemNum, &itemtype, &itemhandle, &borderRect);
  712.     GetMouse(&mouseAt);
  713.     if (PtInRect(mouseAt, &borderRect)) {
  714.         SetCursor(*(GetCursor(1)));
  715.     } else {
  716.         /* This means I'm callng InitCursor every time through my filter */
  717.         /* this is a little excessive (ha!) but doesn't hurt anything. */
  718.         /* You could set a global or something if this really offends you */
  719.         InitCursor();
  720.         
  721.     }
  722. } /* end IBeamIt */
  723.  
  724. /* Gets the ControlHandle for the item you want in the dialog box thebox.  */
  725. /* Handy for setting checkboxes and radio buttons */
  726. /* This is the _most_ copied routine from this file */
  727. ControlHandle SnatchHandle(DialogPtr thebox, short theGetItem)
  728. {
  729.     short itemtype;
  730.     Rect itemrect;
  731.     Handle thandle;
  732.     
  733.     GetDItem(thebox, theGetItem, &itemtype, &thandle, &itemrect);
  734.     return((ControlHandle)thandle);
  735. } /* end SnatchHandle */
  736.  
  737. /* This little routine adjusts the scroll bar during TrackControl */
  738. pascal void DoScrollArrows(ControlHandle theControl, short thePart)
  739. {
  740.     short currentVal = GetCtlValue(theControl);
  741.     short offSet = 0;
  742.     switch (thePart) {
  743.         case inUpButton:
  744.             offSet = -1;
  745.             break;
  746.         case inDownButton:
  747.             offSet = 1;
  748.             break;
  749.         case inPageUp:
  750.             offSet = -3;
  751.             break;
  752.         case inPageDown:
  753.             offSet = 3;
  754.             break;
  755.             
  756.     }
  757.     /* set the control value to the new one, as long as it doesn't pass limits */
  758.     currentVal += offSet;
  759.     if (currentVal < 1)
  760.         currentVal = 1;
  761.     if (currentVal > 10)
  762.         currentVal = 10;
  763.     SetCtlValue(theControl, currentVal);
  764.     
  765. } /* end DoScrollArrows */
  766.  
  767. short HasSelectionRange(DialogPeek inputDialog)
  768. {
  769.     TEHandle theTERecord = inputDialog->textH;
  770.     short returnVal = (*theTERecord)->selEnd -(*theTERecord)->selStart;
  771.     
  772.     return(returnVal);
  773. } /* end HasSelectionRange */
  774.  
  775. /* This NOP routine is here in case the ShortenDITL call is not */
  776. /* available but the new dialog manager calls are.  In that case I don't */
  777. /* want to have the bordering box, but I have to have the user item */
  778. /* pointing at something */
  779. pascal void NOPRoutine(WindowPtr dwind, short dinum)
  780. {
  781. #pragma unused (dwind,dinum)
  782. } /* end NOPRoutine */
  783.  
  784. /* Swiped as was from Sample.c */
  785. Boolean TrapAvailable(short tNumber, TrapType tType)
  786. {
  787.     SysEnvRec Mac;
  788.     /* I didn't make the environs record global because I just don't use it anywhere else */
  789.     SysEnvirons(kSysEnvironsVersion, &Mac);
  790.     if ((tType == ToolTrap) && (Mac.machineType > envMachUnknown) && (Mac.machineType < envMacII)) {    /* it's a 512KE, Plus, or SE */
  791.         tNumber = tNumber & 0x03FF;
  792.         if (tNumber > 0x01FF)                               /* which means the tool traps */
  793.             tNumber = _Unimplemented;                       /* only go to 0x01FF */
  794.     }
  795.     return NGetTrapAddress(tNumber, tType) != GetTrapAddress(_Unimplemented);
  796. }
  797.  
  798. /*TrapAvailable*/
  799.